---
title: Thumbnail Plugin
description: Adds a sidebar with thumbnail images for quick page navigation, with built-in virtualization for high performance.
searchable: true
---

# Thumbnail Plugin

The Thumbnail Plugin adds a classic sidebar view with small, clickable previews of each page. It's an intuitive way for users to get an overview of the document and quickly jump to a specific page.

For optimal performance with long documents, the plugin uses virtualization, rendering only the thumbnail images that are currently visible in the sidebar's viewport.

## Installation

This plugin needs the **Render plugin** to work. The **Scroll plugin** is optional but required for the auto-scroll feature.

```sh npm2yarn
npm install @embedpdf/plugin-thumbnail @embedpdf/plugin-render @embedpdf/plugin-scroll
````

## Registration

Import `ThumbnailPluginPackage` and its dependencies, then add them to the `plugins` array. The dependencies should be registered before the thumbnail plugin.

```tsx {6, 18-20}
import { createPluginRegistration } from '@embedpdf/core'
import { EmbedPDF } from '@embedpdf/core/react'
// ... other imports
import { RenderPluginPackage } from '@embedpdf/plugin-render/react'
import { ScrollPluginPackage } from '@embedpdf/plugin-scroll/react'
import { ThumbnailPluginPackage } from '@embedpdf/plugin-thumbnail/react'

const plugins = [
  // ... other essential plugins
  createPluginRegistration(LoaderPluginPackage, { /* ... */ }),
  createPluginRegistration(ViewportPluginPackage),

  // Register dependencies first
  createPluginRegistration(RenderPluginPackage),
  createPluginRegistration(ScrollPluginPackage),

  // Register and configure the thumbnail plugin
  createPluginRegistration(ThumbnailPluginPackage, {
    width: 120, // Sets the width of thumbnail images
  }),
]
```

## Usage

The plugin features two main components: `<ThumbnailsPane />` (the virtualized container) and `<ThumbImg />` (for rendering the page image).

### Building a Thumbnail Sidebar

You'll typically place `<ThumbnailsPane />` in a sidebar next to your main `<Viewport />`. It uses a **render prop** pattern, where you provide a function as its child. This function gets called for each visible thumbnail, receiving metadata (`m`) about its dimensions and position. You then use this metadata to style your thumbnail container, inside of which you'll render the `<ThumbImg meta={m} />` component.

To handle navigation, you can use the `useScroll` hook to get the `scrollToPage` function and the `currentPage` for highlighting the active thumbnail.

### Using the `meta` Object

The `meta` object passed to your render prop contains pre-calculated values that are crucial for the plugin's virtualization and scrolling logic to work correctly. Here’s a breakdown of the key properties and how to use them:

  * `m.top`: The absolute vertical position of the thumbnail wrapper. **You must apply this to your wrapper element's `top` style.**
  * `m.wrapperHeight`: The total height of the thumbnail's container, including the image, label, and padding. **You must apply this to your wrapper element's `height` style.**
  * `m.width` & `m.height`: The dimensions of the thumbnail image itself. **Apply these to the element that contains the `<ThumbImg />` component.**
  * `m.labelHeight`: The height reserved for the page label.
  * `m.padding`: The padding around the thumbnail image.

By correctly applying `top` and `wrapperHeight`, you ensure that the virtualized layout is rendered without gaps or overlaps.

```tsx
import { useScroll } from '@embedpdf/plugin-scroll/react';
import { ThumbnailsPane, ThumbImg } from '@embedpdf/plugin-thumbnail/react';

const ThumbnailSidebar = () => {
  const { state, provides } = useScroll();

  return (
    <ThumbnailsPane>
      {(m) => {
        const isActive = state.currentPage === m.pageIndex + 1;
        return (
          <div
            key={m.pageIndex}
            style={{
              position: 'absolute',
              top: m.top,
              height: m.wrapperHeight,
              // ... other wrapper styles
            }}
            onClick={() => provides?.scrollToPage({ pageNumber: m.pageIndex + 1 })}
          >
            <div 
              style={{ 
                border: `2px solid ${isActive ? 'blue' : 'grey'}`,
                width: m.width,
                height: m.height,
              }}
            >
              <ThumbImg meta={m} />
            </div>
            <span style={{ height: m.labelHeight }}>
              {m.pageIndex + 1}
            </span>
          </div>
        );
      }}
    </ThumbnailsPane>
  );
};
```

## Live Example

This example shows a complete PDF viewer with a thumbnail sidebar. Clicking a thumbnail will navigate the main document, and the active thumbnail is highlighted with a blue border.

import { PDFViewer } from '../code-examples/thumbnail-example';

<PDFViewer />

## API Reference

### Configuration (`ThumbnailPluginConfig`)

| Option | Type | Description |
| :--- | :--- | :--- |
| **`width`** | `number` | The width of the thumbnail image in CSS pixels. **Default**: `120` |
| **`gap`** | `number` | The vertical space between each thumbnail in CSS pixels. **Default**: `8` |
| **`buffer`** | `number` | The number of off-screen thumbnails to render above and below the visible area. **Default**: `3` |
| **`labelHeight`** | `number` | The height reserved for the page number label below the image. **Default**: `16` |
| **`autoScroll`** | `boolean` | If `true`, the sidebar automatically scrolls to keep the current page's thumbnail in view. **Default**: `true` |
| **`scrollBehavior`**| `string` | The scroll animation (`'smooth'` or `'auto'`). **Default**: `'smooth'` |
| **`imagePadding`** | `number` | Padding inside the thumbnail's border, around the image itself. **Default**: `0` |
| **`paddingY`** | `number` | Vertical padding for the top and bottom of the entire thumbnail container. **Default**: `0` |

### Component: `<ThumbnailsPane />`

The virtualized scroll container for the thumbnails.

| Prop | Type | Description |
| :--- | :--- | :--- |
| **`children`** | `(meta: ThumbMeta) => ReactNode` | **(Required)** A render prop function that receives thumbnail metadata and returns the component for a single thumbnail. |

### Component: `<ThumbImg />`

Renders the rasterized image for a single thumbnail.

| Prop | Type | Description |
| :--- | :--- | :--- |
| **`meta`** | `ThumbMeta` | **(Required)** The metadata object for the thumbnail, provided by the `<ThumbnailsPane />` render prop. |

### Hook: `useThumbnailCapability()`

Provides access to the plugin's methods, though direct interaction is rarely needed due to the `autoScroll` feature.

#### Returns

| Property | Type | Description |
| :--- | :--- | :--- |
| **`provides`**| `ThumbnailCapability \| null` | An object with methods to interact with the plugin, or `null` if not ready. |

#### `ThumbnailCapability` Methods

| Method | Description |
| :--- | :--- |
| **`scrollToThumb(pageIndex)`** | Programmatically scrolls the thumbnail sidebar to make the specified page thumbnail visible. |
| **`renderThumb(pageIndex, dpr)`**| A low-level method to manually trigger the rendering of a specific thumbnail image. Returns a `Task<Blob>`. |